using SqlSugar;
using IM.Easy.Core.Services;
using IM.Easy.Core.Utils;
using IM.Easy.Infrastructure.Query;
using IM.Easy.Core.Extensions;
using IM.Easy.Entity.System;
using IM.Easy.SystemServices.IServices;
using IM.Easy.SystemServices.Dtos.Department;
using Mapster;
using IM.Easy.Infrastructure.Constants;
using System.Linq;

namespace IM.Easy.SystemServices.Services
{
    public class DepartmentService : AppServices<SysDepartment>, IDepartmentService
    {

        public DepartmentService(ISqlSugarClient db) : base(db)
        {

        }

        public DepartmentResponseDto Create(SysDepartmentCreateDto entity)
        {
            if (!DeptValidate(entity, out string msg)) ExceptionUtils.ThrowBusinessException(msg);
            var dept = entity.Adapt<SysDepartment>();
            // TODO: 添加创建逻辑
            dept = Context.Insertable(dept).ExecuteReturnEntity();
            return dept.Adapt<DepartmentResponseDto>();
        }

        public DepartmentResponseDto GetOrg(long id)
        {
            var org = Context
                        .Queryable<SysDepartment>()
                        .Includes(s => s.Parent.ToList(it => new SysDepartment { Id = it.Id, Name = it.Name, Type = it.Type }))
                        .Includes(s => s.Creator.ToList(it => new SysUser { Id = it.Id, NickName = it.NickName, UserName = it.UserName }))
                        .Includes(s => s.Updater.ToList(it => new SysUser { Id = it.Id, NickName = it.NickName, UserName = it.UserName }))
                        .Includes(s => s.Manager.ToList(it => new SysUser { Id = it.Id, NickName = it.NickName, UserName = it.UserName }))
                        .InSingle(id)
                        .Adapt<DepartmentResponseDto>();
            return org;
        }

        public PageResponse<DepartmentResponseDto> GetPageList(SysDepartmentQueryDto query)
        {
            var queryable = Db.Queryable<SysDepartment>();
            var exp = Expressionable.Create<SysDepartment>();
            exp = exp.AndIF(!string.IsNullOrEmpty(query.Name), s => s.Name.Contains(query.Name))
                .AndIF(query.IsActive.HasValue, s => s.IsActive == query.IsActive.Value)
                .AndIF(query.Pid != default, s => s.ParentId == query.Pid);

            var page = queryable
                 .Where(exp.ToExpression())
                 .ToPageList<SysDepartment, DepartmentResponseDto>(query);
            return page;
        }

        /// <summary>
        /// 获取部门组织树
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public List<DepartmentResponseDto> GetTree(SysDepartmentTreeQueryDto query)
        {
            var queryable = Db.Queryable<SysDepartment>();
            var exp = Expressionable.Create<SysDepartment>();
            exp = exp.AndIF(!query.IncludeSelf, s => s.Id != query.SelfId)
                    .AndIF(query.IsActive.HasValue, s => s.IsActive == query.IsActive.Value);
            var list = queryable
                    .Where(exp.ToExpression())
                    .OrderBy(s => s.Order)
                    .ToTree(s => s.Children, s => s.ParentId, query.RootId);
            return list.Adapt<List<DepartmentResponseDto>>();
        }

        /// <summary>
        /// 获取未知部门
        /// </summary>
        public DepartmentResponseDto GetUnknowDepartment()
        {
            return new DepartmentResponseDto
            {
                Name = "未知部门",
                Code = "-1",
                IsActive = true,
                IsDeleted = false,
                IsSystem = true,
                Order = -1,
                Type = OrgTypeConstant.Virtual,
            };
        }

        /// <summary>
        /// 查询所有子节点
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public List<DepartmentResponseDto> GetChildrens(SysDepartmentTreeQueryDto query)
        {
            var queryable = Db.Queryable<SysDepartment>();
            var exp = Expressionable.Create<SysDepartment>();
            exp = exp.AndIF(query.IsActive.HasValue, s => s.IsActive == query.IsActive.Value);
            var list = queryable
                    .Where(exp.ToExpression())
                    .ToChildList(s => s.ParentId, query.SelfId, query.IncludeSelf);

            return list.Adapt<List<DepartmentResponseDto>>();
        }

        public bool Update(SysDepartmentCreateDto createDto)
        {
            if (!DeptValidate(createDto, out string msg)) ExceptionUtils.ThrowBusinessException(msg);
            var dept = GetById(createDto.Id);
            dept = createDto.Adapt(dept);
            return Db.Updateable(dept).ExecuteCommandHasChange();
        }

        /// <summary>
        /// 删除部门
        /// </summary>
        /// <returns></returns>
        public bool DeleteDept(long id)
        {
            var hasUser = Context.Queryable<SysUser>().Any(s => s.DeptId == id);
            if (hasUser)
            {
                ExceptionUtils.ThrowBusinessException("请移除机构组织下所有账号再试");
            }
            var hasChildren = Context.Queryable<SysDepartment>().Any(s => s.ParentId == id);
            if (hasChildren)
            {
                ExceptionUtils.ThrowBusinessException("请删除机构组织下的子节点");
            }
            return base.DeleteById(id);
        }

        /// <summary>
        /// 通过部门管理员获取部门
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<DepartmentResponseDto> GetByManager(long id)
        {
            var depts = Db.Queryable<SysDepartment>()
                .Where(s => s.ManagerId == id)
                .ToList();

            return depts.Adapt<List<DepartmentResponseDto>>();
        }

        /// <summary>
        /// 更新组织类型
        /// </summary>
        /// <param name="orgTypeDto"></param>
        /// <returns></returns>
        public bool SetOrgType(SysOrgTypeDto orgTypeDto)
        {
            List<string> subOrgTypes = [];
            bool allValid = true;
            //向下检查
            var currentSubOrgTypes = Context.Queryable<SysDepartment>().Where(s => s.ParentId == orgTypeDto.Id)
                .Select(s => s.Type)
                .Where(s => !string.IsNullOrEmpty(s))
                .ToList();
            subOrgTypes = OrgTypeConstant.GetSubOrgTypes(orgTypeDto.Type);
            allValid = currentSubOrgTypes.All(x => subOrgTypes.Contains(x));
            if (!allValid)
            {
                ExceptionUtils.ThrowBusinessException("无法调整为当前组织类型");
            }
            //向上检查
            var currentParentOrgTypes = Context.Queryable<SysDepartment>()
                .InnerJoin<SysDepartment>((c, p) => c.ParentId == p.Id)
                .Where((c, p) => c.Id == orgTypeDto.Id)
                .Select((c, p) => p.Type)
                .First();

            if (!string.IsNullOrEmpty(currentParentOrgTypes))
            {
                subOrgTypes = OrgTypeConstant.GetSubOrgTypes(currentParentOrgTypes);
                allValid = subOrgTypes.Contains(orgTypeDto.Type);
                if (!allValid)
                {
                    ExceptionUtils.ThrowBusinessException("无法调整为当前组织类型");
                }
            }


            Update(s => s.Type == orgTypeDto.Type, s => s.Id == orgTypeDto.Id);
            return true;
        }

        /// <summary>
        /// 获取导出的组织机构数据
        /// </summary>
        public List<OrgExcelDto> GetExportOrg(SysDepartmentQueryDto param)
        {
            var result = GetPageList(param);
            var queryable = Query(param);
            var data = queryable.ToList<SysDepartment, OrgExcelDto>();
            return data;
        }



        #region private

        /// <summary>
        /// 部门编码校验
        /// </summary>
        /// <param name="roleId">角色ID（更新时需要排除自身）</param>
        /// <param name="code">权限字符</param>
        /// <param name="msg">返回校验结果信息</param>
        /// <returns>true：校验通过；false：校验失败</returns>
        private bool CodeValidate(long roleId, string code, out string msg)
        {
            msg = string.Empty;

            // 1. 空值或空白字符串检查
            if (string.IsNullOrWhiteSpace(code))
            {
                msg = "部门编码不能为空";
                return false;
            }

            // 3. 长度检查（根据业务需求进行调整）
            int maxLength = 20;
            if (code.Length > maxLength)
            {
                msg = $"部门编码长度不能超过 {maxLength} 个字符";
                return false;
            }

            // 4. 使用 SqlSugar 进行重复校验（排除自身角色ID）
            bool exist = Context.Queryable<SysDepartment>()
                                .Any(r => r.Code == code && r.Id != roleId);
            if (exist)
            {
                msg = $"部门编码【{code}】已存在，请更换后重试。";
                return false;
            }

            msg = "校验成功";
            return true;
        }

        /// <summary>
        /// 组织机构合法性校验
        /// </summary>
        /// <param name="role">组织机构实体</param>
        /// <param name="msg">返回校验结果信息</param>
        /// <returns>true：校验通过；false：校验失败</returns>
        private bool DeptValidate(SysDepartmentCreateDto dept, out string msg)
        {
            if (!CodeValidate(dept.Id, dept.Code, out msg)) return false;
            msg = "校验成功";
            return true;
        }

        private ISugarQueryable<SysDepartment> Query(SysDepartmentQueryDto query)
        {
            var queryable = Db.Queryable<SysDepartment>();
            var exp = Expressionable.Create<SysDepartment>();
            exp = exp.AndIF(!string.IsNullOrEmpty(query.Name), s => s.Name.Contains(query.Name))
                .AndIF(query.IsActive.HasValue, s => s.IsActive == query.IsActive.Value)
                .AndIF(query.Pid != default, s => s.ParentId == query.Pid);

            queryable = queryable
                 .Where(exp.ToExpression());

            return queryable;
        }

        #endregion
    }
}
